"""
TZCANTransmitter: 基于 python-can 的通用 CAN/CAN-FD 发送/接收实现
- 继承 /home/tz4/CanMotorCtroller/CANMessageTransmitter.py 中的抽象基类 CANMessageTransmitter
- 使用 socketcan 接口初始化（参考 can_loopback_test.py）
- 提供与基类一致的方法签名，方便在各模块中替换或直接调用
"""
import time
from typing import Tuple, List, Optional

import can
from CANMessageTransmitter import CANMessageTransmitter

# 与其它模块保持一致的常量（可按需扩展）
TYPE_CAN = 0
TYPE_CANFD = 1
STATUS_OK = 1


class TZCANTransmitter(CANMessageTransmitter):
    """
    使用 python-can 封装的 CAN/CAN-FD 发送接收器，实现抽象基类要求的方法。

    注意：
    - 在 Linux socketcan 下，波特率等物理参数需通过系统命令配置：
      例如：`sudo ip link set can0 up type can bitrate 500000`
    - 本类的 init_can_device 返回 python-can 的 Bus 句柄，作为 channel_handle 使用。
    - 支持 CAN 与 CAN-FD（is_fd）。CAN-FD 的 brs、esi 通过 Message 属性设置。
    """

    def __init__(self, channel_handle: can.BusABC):
        super().__init__(channel_handle)
        self.bus: can.BusABC = channel_handle

    def _send_can_data(
        self,
        send_id: int,
        data_list: List[int],
        is_ext_frame: bool = False,
        canfd_mode: bool = False,
        brs: int = 0,
        esi: int = 0,
    ) -> bool:
        """发送 CAN/CAN-FD 数据。
        - send_id: 报文 ID
        - data_list: 数据字节列表（CAN: ≤8, CAN-FD: ≤64）
        - is_ext_frame: 是否扩展帧（29位ID）
        - canfd_mode: 是否使用 CAN-FD
        - brs: Bit Rate Switch（CAN-FD 专用，1=启用）
        - esi: Error State Indicator（CAN-FD 专用，1=错误状态）
        返回：True/False 是否发送成功
        """
        try:
            # 校验 bus 句柄
            if not isinstance(self.bus, can.BusABC):
                print("❌ 无效的通道句柄，未初始化 Bus")
                return False

            # 长度校验
            if canfd_mode:
                if len(data_list) > 64:
                    print(f"❌ CAN-FD 数据长度超限（{len(data_list)} > 64）")
                    return False
            else:
                if len(data_list) > 8:
                    print(f"❌ CAN 数据长度超限（{len(data_list)} > 8）")
                    return False

            msg = can.Message(
                arbitration_id=send_id,
                data=bytes(bytearray(data_list)),
                is_extended_id=bool(is_ext_frame),
                is_fd=bool(canfd_mode),
                bitrate_switch=bool(brs),
                error_state_indicator=bool(esi),
            )
            self.bus.send(msg)
            return True
        except can.CanError as e:
            print(f"❌ 发送 CAN 报文失败: {e}")
            return False
        except Exception as e:
            print(f"❌ 发送过程异常: {e}")
            return False

    def _receive_can_data(
        self,
        target_id: Optional[int] = None,
        timeout: float = 5,
        is_ext_frame: Optional[bool] = None,
        canfd_mode: bool = False,
    ) -> Tuple[bool, List[int]]:
        """接收 CAN/CAN-FD 数据。
        - target_id: 期望的报文 ID（None 表示接受任何报文）
        - timeout: 超时时间（秒）
        - is_ext_frame: 期望扩展帧标志（None 不强制）
        - canfd_mode: 是否期望接收 CAN-FD 报文（用于过滤）
        返回：(是否成功, 数据列表)
        """
        if not isinstance(self.bus, can.BusABC):
            print("❌ 无效的通道句柄，未初始化 Bus")
            return False, []

        end_ts = time.time() + (timeout if timeout is not None else 0)
        remaining = timeout

        while True:
            try:
                msg = self.bus.recv(timeout=max(0.0, remaining) if timeout is not None else None)
            except can.CanError as e:
                print(f"❌ 接收 CAN 报文失败: {e}")
                return False, []
            except Exception as e:
                print(f"❌ 接收过程异常: {e}")
                return False, []

            if msg is None:
                # 超时
                return False, []

            # 过滤 ID
            if target_id is not None and msg.arbitration_id != target_id:
                # 未匹配，继续等待直到超时
                pass
            else:
                # 可选过滤扩展帧
                if is_ext_frame is not None and bool(msg.is_extended_id) != bool(is_ext_frame):
                    pass
                else:
                    # 可选过滤 FD
                    if canfd_mode and not msg.is_fd:
                        pass
                    else:
                        return True, list(msg.data)

            if timeout is None:
                # 不设超时则继续等待
                continue
            remaining = end_ts - time.time()
            if remaining <= 0:
                return False, []

    @staticmethod
    def _resolve_channel_name(ch: int) -> str:
        """将数字通道映射为 socketcan 接口名。"""
        return f"can{int(ch)}"

    @staticmethod
    def init_can_device(
        baud_rate: int = 500000,
        dbit_baud_rate: int = 2000000,
        channels: List[int] = [0],
        can_type: int = TYPE_CAN,
        canfd_standard: int = 0,
        channel_count: Optional[int] = None,
    ) -> Tuple[dict, Optional[can.BusABC], Optional[can.BusABC]]:
        """初始化 CAN 设备（socketcan）。
        返回：(m_dev, ch0, ch1)，其中 ch0/ch1 为 python-can 的 Bus 句柄。

        说明：
        - socketcan 接口的速率需在系统层配置（本函数仅打开接口）。
        - channels 列表中的元素映射为 'canX' 接口，例如 0 -> 'can0'。
        """
        buses = {}
        ch0 = None
        ch1 = None

        for ch in channels:
            ch_name = TZCANTransmitter._resolve_channel_name(ch)
            try:
                bus = can.interface.Bus(channel=ch_name, interface='socketcan')
                buses[ch] = bus
                if ch == 0:
                    ch0 = bus
                elif ch == 1:
                    ch1 = bus
                print(f"✅ 已打开接口 {ch_name}（socketcan）")
            except OSError as e:
                print(f"❌ 打开接口 {ch_name} 失败: {e}")
                print(f"请先在系统中启用并配置速率，例如: sudo ip link set {ch_name} up type can bitrate {baud_rate}")
            except Exception as e:
                print(f"❌ 初始化接口 {ch_name} 异常: {e}")

        m_dev = {
            "backend": "python-can",
            "buses": buses,
            "config": {
                "baud_rate": baud_rate,
                "dbit_baud_rate": dbit_baud_rate,
                "can_type": can_type,
                "canfd_standard": canfd_standard,
                "channels": channels,
            },
        }
        return m_dev, ch0, ch1

    @staticmethod
    def close_can_device(
        m_dev: dict,
        channel_handle0: Optional[can.BusABC] = None,
        channel_handle1: Optional[can.BusABC] = None,
    ) -> int:
        """关闭 CAN 设备与通道。
        - 对传入的 Bus 逐一 shutdown
        返回：STATUS_OK（1）以与既有代码保持一致
        """
        try:
            # 先关闭显式传入的句柄
            for bus in [channel_handle0, channel_handle1]:
                if isinstance(bus, can.BusABC):
                    try:
                        bus.shutdown()
                    except Exception:
                        pass

            # 再关闭 m_dev 集合中的句柄
            if isinstance(m_dev, dict) and "buses" in m_dev:
                for _, bus in m_dev["buses"].items():
                    try:
                        if isinstance(bus, can.BusABC):
                            bus.shutdown()
                    except Exception:
                        pass
            print("✅ CAN 接口已关闭")
            return STATUS_OK
        except Exception as e:
            print(f"⚠️ 关闭接口过程中出现异常: {e}")
            return STATUS_OK